﻿using System.Text;

namespace Community.CsharpSqlite.Entity
{
    public class Parse
    {
        public sqlite3 db; /* The main database structure */
        public int rc; /* Return code from execution */
        public string zErrMsg; /* An error message */
        public Vdbe pVdbe; /* An engine for executing database bytecode */
        public byte colNamesSet; /* TRUE after OPCode.OP_ColumnName has been issued to pVdbe */
        public byte nameClash; /* A permanent table name clashes with temp table name */
        public byte checkSchema; /* Causes schema cookie check after an error */
        public byte nested; /* Number of nested calls to the parser/code generator */
        public byte parseError; /* True after a parsing error.  Ticket #1794 */
        public byte nTempReg; /* Number of temporary registers in aTempReg[] */
        public byte nTempInUse; /* Number of aTempReg[] currently checked out */
        public int[] aTempReg = new int[8]; /* Holding area for temporary registers */
        public int nRangeReg; /* Size of the temporary register block */
        public int iRangeReg; /* First register in temporary register block */
        public int nErr; /* Number of errors seen */
        public int nTab; /* Number of previously allocated VDBE cursors */
        public int nMem; /* Number of memory cells used so far */
        public int nSet; /* Number of sets used so far */
        public int ckBase; /* Base register of data during check constraints */
        public int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
        public int iCacheCnt; /* Counter used to generate aColCache[].lru values */
        public byte nColCache; /* Number of entries in the column cache */
        public byte iColCache; /* Next entry of the cache to replace */

        public yColCache[] aColCache = new yColCache[Const.SQLITE_N_COLCACHE];
                           /* One for each valid column cache entry */

        public uint writeMask; /* Start a write transaction on these databases */
        public uint cookieMask; /* ulong of schema verified databases */
        public byte isMultiWrite; /* True if statement may affect/insert multiple rows */
        public byte mayAbort; /* True if statement may throw an ABORT exception */
        public int cookieGoto; /* Address of OPCode.OP_Goto to cookie verifier subroutine */
        public int[] cookieValue = new int[Const.SQLITE_MAX_ATTACHED + 2]; /* Values of cookies to verify */
#if !SQLITE_OMIT_SHARED_CACHE
public int nTableLock;         /* Number of locks in aTableLock */
public TableLock[] aTableLock; /* Required table locks for shared-cache mode */
#endif
        public int regRowid; /* Register holding rowid of CREATE TABLE entry */
        public int regRoot; /* Register holding root page number for new objects */
        public AutoincInfo pAinc; /* Information about AUTOINCREMENT counters */
        public int nMaxArg; /* Max args passed to user function by sub-program */

        /* Information used while coding trigger programs. */
        public Parse pToplevel; /* Parse structure for main program (or NULL) */
        public Table pTriggerTab; /* Table triggers are being coded for */
        public uint oldmask; /* Mask of old.* columns referenced */
        public uint newmask; /* Mask of new.* columns referenced */
        public byte eTriggerOp; /* TokenKeyword.TK_UPDATE, TokenKeyword.TK_INSERT or TokenKeyword.TK_DELETE */
        public byte eOrconf; /* Default ON CONFLICT policy for trigger steps */
        public byte disableTriggers; /* True to disable triggers */

        /* Above is constant between recursions.  Below is reset before and after
      ** each recursion */

        public int nVar; /* Number of '?' variables seen in the SQL so far */
        public int nVarExpr; /* Number of used slots in apVarExpr[] */
        public int nVarExprAlloc; /* Number of allocated slots in apVarExpr[] */
        public Expr[] apVarExpr; /* Pointers to :aaa and $aaaa wildcard expressions */
        public Vdbe pReprepare; /* VM being reprepared (sqlite3Reprepare()) */
        public int nAlias; /* Number of aliased result set columns */
        public int nAliasAlloc; /* Number of allocated slots for aAlias[] */
        public int[] aAlias; /* Register used to hold aliased result */
        public byte explain; /* True if the EXPLAIN flag is found on the query */
        public Token sNameToken; /* Token with unqualified schema object name */
        public Token sLastToken = new Token(); /* The last token parsed */
        public StringBuilder zTail; /* All SQL text past the last semicolon parsed */
        public Table pNewTable; /* A table being constructed by CREATE TABLE */
        public Trigger pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
        public string zAuthContext; /* The 6th parameter to db.xAuth callbacks */
#if !SQLITE_OMIT_VIRTUALTABLE
public Token sArg;                /* Complete text of a module argument */
public byte declareVtab;            /* True if inside sqlite3_declare_vtab() */
public int nVtabLock;             /* Number of virtual tables to lock */
public Table[] apVtabLock;        /* Pointer to virtual tables needing locking */
#endif
        public int nHeight; /* Expression tree height of current sub-select */
        public Table pZombieTab; /* List of Table objects to delete after code gen */
        public TriggerPrg pTriggerPrg; /* Linked list of coded triggers */

        // We need to create instances of the col cache
        public Parse()
        {
            for (int i = 0; i < aColCache.Length; i++)
            {
                aColCache[i] = new yColCache();
            }
        }

        public void ResetMembers() // Need to clear all the following variables during each recursion
        {
            nVar = 0;
            nVarExpr = 0;
            nVarExprAlloc = 0;
            apVarExpr = null;
            nAlias = 0;
            nAliasAlloc = 0;
            aAlias = null;
            explain = 0;
            sNameToken = new Token();
            sLastToken = new Token();
            zTail.Length = 0;
            pNewTable = null;
            pNewTrigger = null;
            zAuthContext = null;
#if !SQLITE_OMIT_VIRTUALTABLE
sArg = new Token();
declareVtab = 0;
nVtabLock = 0;
apVtabLoc = null;
#endif
            nHeight = 0;
            pZombieTab = null;
            pTriggerPrg = null;
        }

        private readonly Parse[] SaveBuf = new Parse[10]; //For Recursion Storage

        public void RestoreMembers() // Need to clear all the following variables during each recursion
        {
            if (SaveBuf[nested] != null)
                nVar = SaveBuf[nested].nVar;
            nVarExpr = SaveBuf[nested].nVarExpr;
            nVarExprAlloc = SaveBuf[nested].nVarExprAlloc;
            apVarExpr = SaveBuf[nested].apVarExpr;
            nAlias = SaveBuf[nested].nAlias;
            nAliasAlloc = SaveBuf[nested].nAliasAlloc;
            aAlias = SaveBuf[nested].aAlias;
            explain = SaveBuf[nested].explain;
            sNameToken = SaveBuf[nested].sNameToken;
            sLastToken = SaveBuf[nested].sLastToken;
            zTail = SaveBuf[nested].zTail;
            pNewTable = SaveBuf[nested].pNewTable;
            pNewTrigger = SaveBuf[nested].pNewTrigger;
            zAuthContext = SaveBuf[nested].zAuthContext;
#if !SQLITE_OMIT_VIRTUALTABLE
sArg = SaveBuf[nested].sArg              ;
declareVtab = SaveBuf[nested].declareVtab;
nVtabLock = SaveBuf[nested].nVtabLock;
apVtabLock = SaveBuf[nested].apVtabLock;
#endif
            nHeight = SaveBuf[nested].nHeight;
            pZombieTab = SaveBuf[nested].pZombieTab;
            pTriggerPrg = SaveBuf[nested].pTriggerPrg;
            SaveBuf[nested] = null;
        }

        public void SaveMembers() // Need to clear all the following variables during each recursion
        {
            SaveBuf[nested] = new Parse();
            SaveBuf[nested].nVar = nVar;
            SaveBuf[nested].nVarExpr = nVarExpr;
            SaveBuf[nested].nVarExprAlloc = nVarExprAlloc;
            SaveBuf[nested].apVarExpr = apVarExpr;
            SaveBuf[nested].nAlias = nAlias;
            SaveBuf[nested].nAliasAlloc = nAliasAlloc;
            SaveBuf[nested].aAlias = aAlias;
            SaveBuf[nested].explain = explain;
            SaveBuf[nested].sNameToken = sNameToken;
            SaveBuf[nested].sLastToken = sLastToken;
            SaveBuf[nested].zTail = zTail;
            SaveBuf[nested].pNewTable = pNewTable;
            SaveBuf[nested].pNewTrigger = pNewTrigger;
            SaveBuf[nested].zAuthContext = zAuthContext;
#if !SQLITE_OMIT_VIRTUALTABLE
SaveBuf[nested].sArg = sArg             ;
SaveBuf[nested].declareVtab = declareVtab;
SaveBuf[nested].nVtabLock = nVtabLock   ;
SaveBuf[nested].apVtabLock = apVtabLock ;
#endif
            SaveBuf[nested].nHeight = nHeight;
            SaveBuf[nested].pZombieTab = pZombieTab;
            SaveBuf[nested].pTriggerPrg = pTriggerPrg;
        }
    };
}